﻿using System.Collections.Generic;
using System.Linq;
using System.Windows.Markup;

using UnityConfiguration.Infrastructure;

namespace UnityConfiguration
{

    [ContentProperty("Items")]
    public class Container : TypeResolvingObject, IContainerConfigurationCommand
    {
        private string _Name;
        private List<IContainerItem> _Items;

        /// <summary>
        /// Name of this container configuration. The config may be retrieved by name.
        /// </summary>
        /// <remarks>This name is only used for lookup from the config file. If not 
        /// specified, this is the default container configuration.
        /// </remarks>
        public string Name {
            get { return string.IsNullOrEmpty(_Name) ? string.Empty : _Name; }
            set { _Name = value; }
        }

        /// <summary>
        /// The collection of <see cref="UnityType"/> that contain the actual configuration entries.
        /// </summary>
        public Types Types {
            get {
                Types types = this.Items.OfType<Types>().SingleOrDefault();
                if (null == types) {
                    return new Types();
                }
                types.TypeResolver = TypeResolver;
                return types;
            }
        }

        /// <summary>
        /// The collection of <see cref="Extension"/> that contain the actual configuration entries.
        /// </summary>
        public Extensions Extensions {
            get {
                Extensions extensions = this.Items.OfType<Extensions>().SingleOrDefault();
                if (null == extensions) {
                    return new Extensions();
                }
                extensions.TypeResolver = TypeResolver;
                return extensions;
            }
        }

        /// <summary>
        /// The collection of extension configuration elements that are used to add
        /// arbitrary new extensions to the configuration file.
        /// </summary>
        public ExtensionConfig ExtensionConfigurations {
            get {
                ExtensionConfig extensionConfig = this.Items.OfType<ExtensionConfig>().SingleOrDefault();
                if (null == extensionConfig) {
                    return new ExtensionConfig();
                }
                extensionConfig.TypeResolver = TypeResolver;
                return extensionConfig;
            }
        }

        /// <summary>
        /// The collection of <see cref="Instances"/> that contain the actual configuration entries.
        /// </summary>
        public Instances Instances {
            get {
                Instances instances = this.Items.OfType<Instances>().SingleOrDefault();
                if (null == instances) {
                    return new Instances();
                }
                instances.TypeResolver = TypeResolver;
                return instances;
            }
        }

        public List<IContainerItem> Items {
            get { return _Items; }
            set { _Items = value; }
        }

        public Container() {
            this.Items = new List<IContainerItem>();
        }

        public override string ToString() {
            return string.IsNullOrEmpty(this.Name) ? base.ToString() : this.Name;
        }

        /// <summary>
        /// Execute this command against the given container.
        /// </summary>
        /// <remarks>
        /// Interface implementors will implement this method to
        /// apply configuration changes to the container.</remarks>
        /// <param name="container">The <see cref="IUnityContainer"/> to configure.</param>
        public void Configure(Microsoft.Practices.Unity.IUnityContainer container) {
            foreach (Extension extension in Extensions) {
                extension.Configure(container);
            }
            foreach (UnityType type in Types) {
                type.Configure(container);
            }

            foreach (Instance instance in Instances) {
                instance.Configure(container);
            }
        }

    }

    public class Types : TypeResolvingCollection<UnityType>, IContainerItem
    {
        public Types() : base() { }

        public UnityType this[string name] {
            get { return this.SingleOrDefault(t => t.Name == name); }
        }

    }

    public class Extensions : TypeResolvingCollection<Extension>, IContainerItem
    {
        public Extensions() : base() { }

    }

    public class ExtensionConfig : TypeResolvingCollection<ExtensionConfiguration>, IContainerItem
    {
        public ExtensionConfig() : base() { }

        public ExtensionConfiguration this[string name] {
            get { return this.SingleOrDefault(ec => ec.Name == name); }
        }
    }

    public class Instances : TypeResolvingCollection<Instance>, IContainerItem
    {
        public Instances() : base() { }

    }
}
